﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using TTGame;

/*
 * TestAnimStuff
 * 测试动画的Layer、动画融合
 *
 *
 * 结论：
 * 1、layer:多个layer的动画，高的会覆盖低的。
 *      如果不同层次使用不同骨骼Mask，就有动画融合的效果了。
 * 2、CrossFade：新动画会以过渡方式。
 *          1.fadeLength不能超过新动画的长度，否则会出现动画卡住。
 *          2.如果当前[没有动画正在播放]，则fade不起效果。
 * 3、Rewind：动画会从头开始播放。
 *          1.如果当前[没有动画正在播放]，则不起效果。
 * 4.[没有动画正在播放]是指：
 *      动画如果设置成Clamp，播放结束后会固定在最后一帧。此时播放结束，不算做正在播放。
 *      注意ClampForever，当固定在最后一帧时，动画是依旧在播放的。
 * 5、播放相同的动画时，如果之前的动画正在播放，则重复播放无效。只有等之前的动画播放结束才行。
 *      如果是Once/Clamp去顶掉之前的Loop/ClampForever相同动画，会导致动画卡住……
 *
 * 使用说明：
 * 1、添加播放表，添加播放组的名称，然后点击playAnim按钮。可以很方便的测试融合动画。
 * 2、如果需要测试不同动画前后的crossFade，可以将前一个动画组的speed调慢一点，然后靠手动改播放组名称（播放组名称写简单点，如a,b,c）来测试查看。
 *
 * ！不写重复代码！
 * @author TTun
 * @date 7/20/2017 9:28:59 AM
 */
[System.Serializable]
public class MixBoneInfo {
    public Transform mixBoneTF;
    public bool isRev;
}

/// <summary>
/// 播放动画的配置参数
/// </summary>
[System.Serializable]
public class AnimPlayerInfo {
    public string animName;
    public int layer = 0;
    public WrapMode wrapMode = WrapMode.Default;
    public float speed = 1;
    public float weight = 1;
    public float fadeTime = 0.1f;
    public AnimationBlendMode blendMode = AnimationBlendMode.Additive;
    public PlayType playType = PlayType.CrossFade;
    public MixBoneInfo[] mixBone;
}

/// <summary>
/// 当前动画状态
/// </summary>
[System.Serializable]
public class AnimStateInfo {
    public string animName;
    public int layer;
    public float length;
    public WrapMode wrapMode;
    public float speed = 1;
    public float weight = 1;
    public float fadeTime = 0.1f;
    public AnimationBlendMode blendMode;
    public PlayType playType = PlayType.CrossFade;

    AnimationState bindstate;

    public AnimStateInfo(AnimationState animState) {
        bindstate = animState;
        RefreshInfo();
    }

    public void RefreshInfo() {
        animName = bindstate.name;
        layer = bindstate.layer;
        length = bindstate.length;
        wrapMode = bindstate.wrapMode;
        speed = bindstate.speed;
        weight = bindstate.weight;
        blendMode = bindstate.blendMode;
    }
}

public enum PlayType {
    CrossFade,
    Blend,
    BlendTowardWeight,
}

[System.Serializable]
public class AnimPlayerSituation {
    public string name;
    public AnimPlayerInfo[] animPlayers;
}

[ExecuteInEditMode]
public class TestAnimStuff : MonoBehaviour {

    public enum AnimLayerID {
        Layer_0,
        Layer_1,
        Layer_2,
        Layer_3,
        Layer_4,
        Layer_5,
    }
    public Animation anim;

    public AnimStateInfo[] m_animStates;

    public List<AnimationState> enablesAnimStates = new List<AnimationState>();

    public string runAnimPlayer;
    public AnimPlayerSituation[] AnimPlayerSituations;

    void Awake() {
        if(anim == null) anim = gameObject.GetComponentInChildren<Animation>();
    }

    void Start() {
        RefreshAnimInfo();
    }

    bool isNeedRefresh = true;
    void Update() {
        isNeedRefresh = RefreshAnimStateInfo();
    }

    /// <summary>
    ///
    /// </summary>
    /// <returns>是否应该继续持续刷新</returns>
    public bool RefreshAnimStateInfo() {
        if(anim == null) {
            return false;
        }
        bool isNeedRefresh = false;

        enablesAnimStates.Clear();
        foreach(AnimationState animState in anim) {
            if(animState.enabled) {
                enablesAnimStates.Add(animState);
                if(isNeedRefresh || animState.wrapMode == WrapMode.Loop || animState.wrapMode == WrapMode.PingPong) {
                    isNeedRefresh = true;
                }
            }
        }
        return isNeedRefresh;
    }

    public void RefreshAnimInfo() {
        if(anim == null) {
            return;
        }
        m_animStates = new AnimStateInfo[anim.GetClipCount()];
        int i = 0;
        foreach(AnimationState state in anim) {
            m_animStates[i++] = new AnimStateInfo(state);
        }

        RefreshAnimStateInfo();
    }

    public void RewindAllAnim() {
        if(anim == null) {
            return;
        }
        anim.Rewind();
    }

    public void PlayAnim(AnimPlayerInfo info) {
        if(anim == null) {
            return;
        }
        string newAnimName = info.animName;
        if(info.mixBone != null && info.mixBone.Length > 0) {
            newAnimName = newAnimName + "_mix";
            if(anim[newAnimName] != null) {
                anim.RemoveClip(newAnimName);
            }
            anim.AddClip(anim[info.animName].clip, newAnimName);
        }

        AnimationState state = anim[newAnimName];
        state.layer = info.layer;
        state.wrapMode = info.wrapMode;
        state.speed = info.speed;
        state.blendMode = info.blendMode;
        foreach(MixBoneInfo mixBone in info.mixBone) {
            if(mixBone != null && mixBone.mixBoneTF != null)
                state.AddMixingTransform(mixBone.mixBoneTF);
        }

        switch(info.playType) {
            case PlayType.CrossFade:
                anim.CrossFade(newAnimName, info.fadeTime);
                break;
            case PlayType.Blend:
                state.weight = info.weight;
                anim.Blend(newAnimName);
                break;
            case PlayType.BlendTowardWeight:
                anim.Blend(newAnimName, info.weight, info.fadeTime);
                break;
        }

        //m_lastState = state;
        RefreshAnimStateInfo();
    }

    public void PlayAnim() {
        foreach(AnimPlayerSituation animSitu in AnimPlayerSituations) {
            if(animSitu.name == runAnimPlayer) {
                foreach(AnimPlayerInfo info in animSitu.animPlayers) {
                    PlayAnim(info);
                }
            }
        }
    }

    public string DumpEnabledAnimStateInfo() {
        string strDump = "";
        foreach(AnimationState animState in enablesAnimStates) {
            strDump += DumpAnimStateInfo(animState);
        }
        return strDump;
    }

    public string DumpAnimStateInfo(AnimationState animState) {
        string strDump = string.Format("[AnimationState]：{0}\nlayer:\t{1}\ntime:{2}/{3}\nwrapMode:{4}\n-----------------------\n",
                                       animState.name,
                                       animState.layer,
                                       animState.time,
                                       animState.length,
                                       animState.wrapMode.ToString());

        return strDump;

    }
}
